package cn.gailvlun.gll.mgr;

import android.util.Log;

import com.alibaba.sdk.android.oss.ClientException;
import com.alibaba.sdk.android.oss.OSS;
import com.alibaba.sdk.android.oss.OSSClient;
import com.alibaba.sdk.android.oss.ServiceException;
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback;
import com.alibaba.sdk.android.oss.callback.OSSProgressCallback;
import com.alibaba.sdk.android.oss.common.OSSLog;
import com.alibaba.sdk.android.oss.common.auth.OSSFederationCredentialProvider;
import com.alibaba.sdk.android.oss.common.auth.OSSFederationToken;
import com.alibaba.sdk.android.oss.model.PutObjectRequest;
import com.alibaba.sdk.android.oss.model.PutObjectResult;
import com.blankj.utilcode.util.Utils;

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import cn.gailvlun.gll.mgr.upload.OSSException;
import cn.gailvlun.gll.net.BuildConfig;
import cn.gailvlun.gll.net.HttpMethods;
import cn.gailvlun.gll.net.base.OssTokenRes;
import cn.gailvlun.gll.util.LogUtil;
import io.reactivex.Flowable;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.SingleEmitter;
import io.reactivex.SingleOnSubscribe;
import io.reactivex.schedulers.Schedulers;



public class UploadMgr {

    private OSS mOss;

    private static UploadMgr INSTANCE = null;
    private UploadMgr() {
        mOss = new OSSClient(Utils.getApp(), BuildConfig.END_POINT, new OSSFederationCredentialProvider() {
            @Override
            public OSSFederationToken getFederationToken() {
                OSSFederationToken ossFederationToken = null;
                try {
                    OssTokenRes ossTokenRes = HttpMethods.getBaseService().getOssToken()
                            .execute().body();
                    if (ossTokenRes != null) {
                        ossFederationToken = new OSSFederationToken(ossTokenRes.getAccessKeyId(), ossTokenRes.getAccessKeySecret(), ossTokenRes.getSecurityToken(), ossTokenRes.getExpiration());
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return ossFederationToken;
            }
        });
        OSSLog.enableLog();
    }

    public static void init() {
        if (INSTANCE == null) {
            synchronized (UploadMgr.class) {
                if (INSTANCE == null) {
                    INSTANCE = new UploadMgr();
                }
            }
        }
    }

    public static UploadMgr getInstance() {
        if (INSTANCE == null) {
            synchronized (UploadMgr.class) {
                if (INSTANCE == null) {
                    INSTANCE = new UploadMgr();
                }
            }
        }
        return INSTANCE;
    }

    public void upload(String objectKey, String uploadFilePath, OSSCompletedCallback<PutObjectRequest, PutObjectResult> callback) {
        PutObjectRequest putObjectRequest = new PutObjectRequest(BuildConfig.IMAGE_BUCKET,
                objectKey, uploadFilePath);
        mOss.asyncPutObject(putObjectRequest, callback);
    }

    public Single<UploadResult<PutObjectRequest, PutObjectResult>> upload(final String objectKey, final String uploadFilePath) {
        return Single.create(new SingleOnSubscribe<UploadResult<PutObjectRequest, PutObjectResult>>() {
            @Override
            public void subscribe(final SingleEmitter<UploadResult<PutObjectRequest, PutObjectResult>> emitter) throws Exception {
                PutObjectRequest por = new PutObjectRequest(BuildConfig.IMAGE_BUCKET, objectKey, uploadFilePath);
                mOss.asyncPutObject(por, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
                    @Override
                    public void onSuccess(PutObjectRequest request, PutObjectResult result) {
                        LogUtil.d("onSuccess()");
                        emitter.onSuccess(UploadResult.create(request, result));
                    }

                    @Override
                    public void onFailure(PutObjectRequest request, ClientException clientException, ServiceException serviceException) {
                        LogUtil.d("onFailure()");
                        emitter.onError(OSSException.create(request, clientException, serviceException));
                    }
                });
            }
        });
    }

    public Single<UploadResult<PutObjectRequest, PutObjectResult>> uploadWithProgress(final String objectKey,
                                                                                      final String uploadFilePath, final OSSProgressCallback<PutObjectRequest> progressCallback) {
        return Single.create(new SingleOnSubscribe<UploadResult<PutObjectRequest, PutObjectResult>>() {
            @Override
            public void subscribe(final SingleEmitter<UploadResult<PutObjectRequest, PutObjectResult>> emitter) throws Exception {
                PutObjectRequest por = new PutObjectRequest(BuildConfig.IMAGE_BUCKET, objectKey, uploadFilePath);
                por.setProgressCallback(progressCallback);
                mOss.asyncPutObject(por, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
                    @Override
                    public void onSuccess(PutObjectRequest request, PutObjectResult result) {
                        LogUtil.d("onSuccess()");
                        emitter.onSuccess(UploadResult.create(request, result));
                    }

                    @Override
                    public void onFailure(PutObjectRequest request, ClientException clientException, ServiceException serviceException) {
                        LogUtil.d("onFailure()");
                        emitter.onError(OSSException.create(request, clientException, serviceException));
                    }
                });
            }
        });
    }

    public Flowable<UploadResult<PutObjectRequest, PutObjectResult>> upload(HashMap<String, String> keyPathMap) {
        Set<Single<UploadResult<PutObjectRequest, PutObjectResult>>> singles = new HashSet<>();
        for (String ossKey : keyPathMap.keySet()) {
            singles.add(upload(ossKey, keyPathMap.get(ossKey)).subscribeOn(Schedulers.io()));
        }

        return Single.merge(singles);
    }






}
